#include "HighlightSelectedPoints.h"
#include <vtkActor.h>
#include <vtkAreaPicker.h>
#include <vtkDataSetMapper.h>
#include <vtkDataSetSurfaceFilter.h>
#include <vtkExtractGeometry.h>
#include <vtkIdFilter.h>
#include <vtkIdTypeArray.h>
#include <vtkInteractorStyleRubberBandPick.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkObjectFactory.h>
#include <vtkPlanes.h>
#include <vtkPointData.h>
#include <vtkPointSource.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkRendererCollection.h>
#include <vtkSmartPointer.h>
#include <vtkUnstructuredGrid.h>
#include <vtkVersion.h>
#include <vtkVertexGlyphFilter.h>

namespace {
	// Define interaction style
	class InteractorStyle : public vtkInteractorStyleRubberBandPick
	{
	public:
		static InteractorStyle* New();
		vtkTypeMacro(InteractorStyle, vtkInteractorStyleRubberBandPick);

		InteractorStyle()
		{
			this->SelectedMapper = vtkSmartPointer<vtkDataSetMapper>::New();
			this->SelectedActor = vtkSmartPointer<vtkActor>::New();
			this->SelectedActor->SetMapper(SelectedMapper);
		}

		virtual void OnLeftButtonUp() override
		{
			vtkNew<vtkNamedColors> colors;

			// Forward events
			vtkInteractorStyleRubberBandPick::OnLeftButtonUp();

			vtkPlanes* frustum =
				static_cast<vtkAreaPicker*>(this->GetInteractor()->GetPicker())
				->GetFrustum();

			vtkNew<vtkExtractGeometry> extractGeometry;
			extractGeometry->SetImplicitFunction(frustum);
			extractGeometry->SetInputData(this->Points);
			extractGeometry->Update();

			vtkNew<vtkVertexGlyphFilter> glyphFilter;
			glyphFilter->SetInputConnection(extractGeometry->GetOutputPort());
			glyphFilter->Update();

			vtkPolyData* selected = glyphFilter->GetOutput();
			qDebug() << "Selected " << selected->GetNumberOfPoints() << " points.";
			qDebug() << "Selected " << selected->GetNumberOfCells() << " cells.";
			this->SelectedMapper->SetInputData(selected);
			this->SelectedMapper->ScalarVisibilityOff();

			vtkIdTypeArray* ids = dynamic_cast<vtkIdTypeArray*>(
				selected->GetPointData()->GetArray("OriginalIds"));
			for (vtkIdType i = 0; i < ids->GetNumberOfTuples(); i++)
			{
				qDebug() << "Id " << i << " : " << ids->GetValue(i);
			}

			this->SelectedActor->GetProperty()->SetColor(
				colors->GetColor3d("Red").GetData());
			this->SelectedActor->GetProperty()->SetPointSize(5);

			this->CurrentRenderer->AddActor(SelectedActor);
			this->GetInteractor()->GetRenderWindow()->Render();
			this->HighlightProp(NULL);
		}

		void SetPoints(vtkSmartPointer<vtkPolyData> points)
		{
			this->Points = points;
		}

	private:
		vtkSmartPointer<vtkPolyData> Points;
		vtkSmartPointer<vtkActor> SelectedActor;
		vtkSmartPointer<vtkDataSetMapper> SelectedMapper;
	};
	vtkStandardNewMacro(InteractorStyle);
} // namespace

HighlightSelectedPoints::HighlightSelectedPoints(QWidget* parent)
	: QMainWindow(parent)
{
	vtkWidget = new QVTKOpenGLNativeWidget(this);
	this->resize(600, 400);
	this->setCentralWidget(vtkWidget);

	vtkNew<vtkNamedColors> colors;

	vtkNew<vtkPointSource> pointSource;
	pointSource->SetNumberOfPoints(20);
	pointSource->Update();

	vtkNew<vtkIdFilter> idFilter;
	idFilter->SetInputConnection(pointSource->GetOutputPort());
	idFilter->SetIdsArrayName("OriginalIds");
	idFilter->Update();

	vtkNew<vtkDataSetSurfaceFilter> surfaceFilter;
	surfaceFilter->SetInputConnection(idFilter->GetOutputPort());
	surfaceFilter->Update();

	vtkPolyData* input = surfaceFilter->GetOutput();

	// Create a mapper and actor
	vtkNew<vtkPolyDataMapper> mapper;
	mapper->SetInputData(input);
	mapper->ScalarVisibilityOff();

	vtkNew<vtkActor> actor;
	actor->SetMapper(mapper);
	actor->GetProperty()->SetPointSize(3);
	actor->GetProperty()->SetColor(colors->GetColor3d("Gold").GetData());

	// Visualize
	vtkNew<vtkRenderer> renderer;
	vtkWidget->renderWindow()->AddRenderer(renderer);

	vtkNew<vtkAreaPicker> areaPicker;
	vtkWidget->interactor()->SetPicker(areaPicker);

	renderer->AddActor(actor);
	renderer->SetBackground(colors->GetColor3d("DarkSlateGray").GetData());

	vtkNew<InteractorStyle> style;
	style->SetPoints(input);
	vtkWidget->interactor()->SetInteractorStyle(style);
}

HighlightSelectedPoints::~HighlightSelectedPoints()
{}
